﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using CC.Utilities;
using CC.Yacht.Exceptions;
using CC.Yacht.Interfaces;
using CC.Yacht.Messages;
using CC.Yacht.Utilities;

namespace CC.Yacht.Server
{
    public class YachtService : IYachtService
    {
        #region Public Properties
        public IYachtServiceCallback CurrentCallback
        {
            get
            {
                return OperationContext.Current.GetCallbackChannel<IYachtServiceCallback>();                
            }
        }
        #endregion

        #region Public Methods
        public void CreateGame(Guid sessionId, Guid lobbyId)
        {
            var response = MessageHelper.CreateResponse<JoinGameResponse>();

            try
            {
                Guid gameId = LobbyManager.CreateGame(lobbyId, SessionManager.GetUserAndKeepAlive(sessionId));
                
                if (gameId != Guid.Empty)
                {
                    response.ClearError();
                    response.GameState = LobbyManager.GetGameState(gameId);
                }
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
                response.ErrorType = exception.ErrorType;
            }

            CurrentCallback.JoinedGame(response);
        }

        public void JoinGame(Guid sessionId, Guid gameId)
        {
            var response = MessageHelper.CreateResponse<JoinGameResponse>();

            try
            {
                if (LobbyManager.JoinGame(gameId, SessionManager.GetUserAndKeepAlive(sessionId)))
                {
                    response.ClearError();
                    response.GameState = LobbyManager.GetGameState(gameId);
                }
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
                response.ErrorType = exception.ErrorType;
            }

            CurrentCallback.JoinedGame(response);
        }

        public void JoinLobby(Guid sessionId, Guid lobbyId)
        {
            var response = MessageHelper.CreateResponse<JoinLobbyResponse>();
            response.LobbyId = lobbyId;

            try
            {
                if (LobbyManager.JoinLobby(lobbyId, SessionManager.GetUserAndKeepAlive(sessionId)))
                {
                    response.ClearError();
                    response.Games = LobbyManager.GetGames(lobbyId);
                    response.Users = LobbyManager.GetUsers(lobbyId);
                }
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
                response.ErrorType = exception.ErrorType;
            }
            
            CurrentCallback.JoinedLobby(response);
        }

        public void LeaveGame(Guid sessionId, Guid gameId)
        {
            try
            {
                LobbyManager.LeaveGame(gameId, SessionManager.GetUserAndKeepAlive(sessionId));
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
            }

            //CurrentCallback.JoinedGame(response); // NOTE: Do I need a LeftGame callback?
        }

        public void LeaveLobby(Guid sessionId, Guid lobbyId)
        {
            LobbyManager.LeaveLobby(lobbyId, sessionId);
        }

        public LoginResponse Login(string email, string password)
        {
            var response = MessageHelper.CreateResponse<LoginResponse>();
            response.SessionId = SessionManager.Login(email, password, CurrentCallback);

            if (response.IsLoggedIn)
            {
                ExtendedUser user = SessionManager.GetUser(response.SessionId);
                response.User = user.ToUser();
                response.ClearError();

                //TODO: Check which lobby (if any) the user is in...

                GameState gameState = LobbyManager.GetGameState(user);
                if (gameState != null)
                {
                    response.GameId = gameState.GameId;
                }
            }

            return response;
        }

        public void Logout(Guid sessionId)
        {
            SessionManager.Logout(sessionId);
        }

        public bool Ping()
        {
            return true;
        }

        public BaseResponse Register(string email, string username, string password)
        {
            var returnValue = MessageHelper.CreateResponse<BaseResponse>();

            try
            {
                if (Database.AddUser(new ExtendedUser(email, username, password, false)))
                {
                    returnValue.ClearError();
                }
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
                returnValue.ErrorType = exception.ErrorType;
            }

            return returnValue;
        }

        public void Roll(Guid sessionId, Guid gameId)
        {
            try
            {
                LobbyManager.Roll(gameId, SessionManager.GetUserAndKeepAlive(sessionId));
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
            }
        }

        public void SendMessage(Guid sessionId, Target target, Guid targetId, string message)
        {
            try
            {
                LobbyManager.SendMessage(target, targetId, SessionManager.GetUserAndKeepAlive(sessionId), message);
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
            }
        }

        public void SetScoreField(Guid sessionId, Guid gameId, ScoreField scoreField)
        {
            try
            {
                LobbyManager.SetScoreField(gameId, SessionManager.GetUserAndKeepAlive(sessionId), scoreField);
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
            }
        }

        public void StartGame(Guid sessionId, Guid gameId)
        {
            try
            {
                LobbyManager.StartGame(gameId, SessionManager.GetUserAndKeepAlive(sessionId));
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
            }            
        }

        public void UpdateDice(Guid sessionId, Guid gameId, Dice dice)
        {
            try
            {
                LobbyManager.UpdateDice(gameId, SessionManager.GetUserAndKeepAlive(sessionId), dice);
            }
            catch (YachtException exception)
            {
                Logging.LogException(exception);
            }
        }
        #endregion
    }
}
